﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace SlXnaAppMangoMotion
{
    using Microsoft.Devices;
    using Microsoft.Devices.Sensors;
    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Windows.Media.Imaging;

    public partial class GamePage : PhoneApplicationPage
    {
        ContentManager contentManager;
        GameTimer timer;
        SpriteBatch spriteBatch;
        UIElementRenderer elementRenderer;

        Teapot teapot;
        bool touchAvailable = false;

        Motion motion;
        PhotoCamera photoCamera;

        // プロジェクトテンプレートそのままのコード
        public GamePage()
        {
            InitializeComponent();

            // アプリケーションからコンテンツ マネージャーを取得します
            contentManager = (Application.Current as App).Content;

            // このページのタイマーを作成します
            timer = new GameTimer();
            timer.UpdateInterval = TimeSpan.FromTicks(333333);
            timer.Update += OnUpdate;
            timer.Draw += OnDraw;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // グラフィックス デバイスの共有モードを設定して XNA レンダリングを有効にします
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(true);

            // 新しい SpriteBatch を作成します。これは、テクスチャの描画に使用できます。
            spriteBatch = new SpriteBatch(SharedGraphicsDeviceManager.Current.GraphicsDevice);

            GraphicsDevice device = SharedGraphicsDeviceManager.Current.GraphicsDevice;

            // Silverlight描画用の設定
            elementRenderer = new UIElementRenderer(this, device.Viewport.Width, device.Viewport.Height);

            teapot = new Teapot(device);

            Microsoft.Xna.Framework.Input.Touch.TouchPanel.EnabledGestures =
                Microsoft.Xna.Framework.Input.Touch.GestureType.FreeDrag
                | Microsoft.Xna.Framework.Input.Touch.GestureType.Pinch;
            touchAvailable = true;

            #region MotionSensor
            if (Motion.IsSupported)
            {
                motion = new Motion();
            }
            else
            {
                MessageBox.Show("モーションセンサーが装備されていません");
                cbMotion.Visibility = System.Windows.Visibility.Collapsed;
            }
            #endregion

            #region CameraPart
            if (useCamera)
            {
                if (PhotoCamera.IsCameraTypeSupported(CameraType.Primary))
                {
                    buttonShutter.Visibility = System.Windows.Visibility.Visible;
                    photoCamera = new PhotoCamera(CameraType.Primary);
                    photoCamera.Initialized += new EventHandler<CameraOperationCompletedEventArgs>(photoCamera_Initialized);
                    photoCamera.CaptureImageAvailable += new EventHandler<ContentReadyEventArgs>(photoCamera_CaptureImageAvailable);

                    viewFinderBrush.SetSource(photoCamera);
                }
                else
                {
                    useCamera = false;
                }
                buttonShutter.Visibility = System.Windows.Visibility.Visible;
            }
            #endregion

            // タイマーを開始します
            timer.Start();

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // タイマーを停止します
            timer.Stop();

            if (cbMotion.IsChecked.Value)
            {
                motion.Stop();
            }
            if (photoCamera != null)
            {
                photoCamera.Dispose();
            }

            // グラフィックス デバイスの共有モードを設定して XNA レンダリングを無効にします
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        /// フレームの更新、衝突チェック、入力の収集、オーディオの再生
        /// などのロジックをページで実行できるようにします。
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            if (touchAvailable)
            {
                HandleGesture();
                teapot.World = dragMtx;

                if (pinchMtx != Matrix.Identity)
                {
                    teapot.View = pinchMtx;
                }
            }
            #region UseMotionSensor
            else
            {
                teapot.World = Matrix.CreateFromYawPitchRoll(0, MathHelper.PiOver2, 0) * motion.CurrentValue.Attitude.RotationMatrix;
            }
            #endregion
        }

        /// <summary>
        /// ページ自体を描画できるようにします。
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            // Silverlight UIエレメントをTextureへ描画
            elementRenderer.Render();

            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);

            // Silverlight UIエレメントを描画
            spriteBatch.Begin();
            spriteBatch.Draw(elementRenderer.Texture, Vector2.Zero, Color.White);
            spriteBatch.End();

            // XNAのTeapotを描画
            teapot.Draw(SharedGraphicsDeviceManager.Current.GraphicsDevice);
        }

        private Matrix dragMtx = Matrix.Identity;
        private Matrix pinchMtx = Matrix.Identity;
        private float cameraDistance = 5f;

        private void HandleGesture()
        {
            while (Microsoft.Xna.Framework.Input.Touch.TouchPanel.IsGestureAvailable)
            {
                var gestureSample = Microsoft.Xna.Framework.Input.Touch.TouchPanel.ReadGesture();
                // Rotation
                if (gestureSample.GestureType == Microsoft.Xna.Framework.Input.Touch.GestureType.FreeDrag)
                {
                    float rate = 0.01f;
                    dragMtx = teapot.World * Matrix.CreateFromYawPitchRoll(gestureSample.Delta.X * rate, gestureSample.Delta.Y * rate, 0f);
                }
                // Scale
                else if (gestureSample.GestureType == Microsoft.Xna.Framework.Input.Touch.GestureType.Pinch)
                {
                    float scale = 1.0f;
                    Vector2 oldPosition1 = new Vector2(gestureSample.Position.X - gestureSample.Delta.X, gestureSample.Position.Y - gestureSample.Delta.Y);
                    Vector2 oldPosition2 = new Vector2(gestureSample.Position2.X - gestureSample.Delta2.X, gestureSample.Position2.Y - gestureSample.Delta2.Y);
                    float oldDistance = Vector2.Distance(oldPosition1, oldPosition2);
                    float newDistance = Vector2.Distance(gestureSample.Position, gestureSample.Position2);
                    scale = newDistance / oldDistance;
                    cameraDistance /= scale;

                    pinchMtx = Matrix.CreateLookAt(new Vector3(0f, 0f, cameraDistance), Vector3.Zero, Vector3.Up);
                }
            }
        }

        private void cbMotion_Checked(object sender, RoutedEventArgs e)
        {
            touchAvailable = false;
            motion.Start();
        }

        private void cbMotion_Unchecked(object sender, RoutedEventArgs e)
        {
            touchAvailable = true;
            motion.Stop();
        }

        private bool useCamera = true;

        void photoCamera_Initialized(object sender, CameraOperationCompletedEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(delegate()
            {
                // Flash! あ～あ、の制御は初期化終了後でないとできない
                photoCamera.FlashMode = FlashMode.Off;
                videoRect.Visibility = System.Windows.Visibility.Visible;
            });
        }

        void photoCamera_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
        {
            Deployment.Current.Dispatcher.BeginInvoke(delegate()
            {   
                // 撮った写真に位置情報、モーション情報を加え、カメラロールに保存する
                BitmapImage photoImage = new BitmapImage();
                photoImage.SetSource(e.ImageStream);
                Image image = new Image();
                image.Source = photoImage;
                videoRect.Children.Add(image);

                if (!touchAvailable)
                {
                    // デバイスの姿勢を記録
                    TextBlock tbDir = new TextBlock();
                    tbDir.Text = String.Format("Direction:Yaw={0:0.000},Pitch={1:0.000},Row={2:0.000}", motion.CurrentValue.Attitude.Yaw, motion.CurrentValue.Attitude.Pitch, motion.CurrentValue.Attitude.Roll);
                    tbDir.FontSize = 20;
                    Canvas.SetTop(tbDir, 360);
                    Canvas.SetLeft(tbDir, 10);
                    videoRect.Children.Add(tbDir);

                    // デバイスの向きを記録
                    using (var compass = new Compass())
                    {
                        compass.Start();
                        while (!compass.IsDataValid)
                        {
                            System.Threading.Thread.Sleep(100);
                        }
                        TextBlock tbHeading = new TextBlock();
                        tbHeading.Text = String.Format("Heading={0:0.000}", compass.CurrentValue.TrueHeading);
                        tbHeading.FontSize = 20;
                        Canvas.SetTop(tbHeading, 400);
                        Canvas.SetLeft(tbHeading, 10);
                        videoRect.Children.Add(tbHeading);
                        compass.Stop();
                    }
                    
                    // デバイスの位置を記録
                    using (var watcher = new System.Device.Location.GeoCoordinateWatcher())
                    {
                        watcher.Start();
                        TextBlock tbLoc = new TextBlock();
                        tbLoc.Text = String.Format("Location:Long={0},Lat={1}", watcher.Position.Location.Longitude, watcher.Position.Location.Latitude);
                        tbLoc.FontSize = 20;
                        Canvas.SetTop(tbLoc, 440);
                        Canvas.SetLeft(tbLoc, 10);
                        videoRect.Children.Add(tbLoc);
                        watcher.Stop();
                    }
                }
                // Canvasに描画した内容を、ビットマップデータ化
                WriteableBitmap photoBitmap = new WriteableBitmap(videoRect,null);
                photoBitmap.Invalidate();

                videoRect.Children.Clear();

                // テンポラリにJPEGファイルを作成して、Camera Rollに保存
                string fileName = String.Format("arsample{0}.jpg", DateTime.Now.ToString("yyyyMMdd_HHmmss"));
                IsolatedStorageFile myStorage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication();
                IsolatedStorageFileStream tmpFileStream = myStorage.OpenFile(fileName, FileMode.Create, FileAccess.Write);
                photoBitmap.SaveJpeg(tmpFileStream, photoBitmap.PixelWidth, photoBitmap.PixelHeight, 0, 100);

                tmpFileStream.Close();
                tmpFileStream = myStorage.OpenFile(fileName, FileMode.Open, FileAccess.Read);
                var library = new Microsoft.Xna.Framework.Media.MediaLibrary();
                library.SavePictureToCameraRoll(fileName, tmpFileStream);
                tmpFileStream.Close();
                myStorage.DeleteFile(fileName);
            });
        }

        private void buttonShutter_Click(object sender, RoutedEventArgs e)
        {
            photoCamera.CaptureImage();
        }

    }
}